package ext;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ProtocolResolver;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

/**
 * @author 北京八维博大科技 薛建新
 * @date 2022年11月8日 10:38:04
 * @Copyright 北京八维博大科技
 */
//https://www.cnblogs.com/markLogZhu/p/12497258.html
//https://juejin.cn/post/7144167544692146183#heading-11
public final class SecondInitializer
		implements ApplicationContextInitializer<AnnotationConfigServletWebServerApplicationContext> {

	@Override
	public void initialize(AnnotationConfigServletWebServerApplicationContext applicationContext) {
		System.out.println(applicationContext.getClass().toString());
//		applicationContext.setClassLoader(null);
//		applicationContext.addProtocolResolver(null);

//		ResourceLoader resourceLoader = new ClassLoaderFilesResourcePatternResolver(applicationContext,this.classLoaderFiles);
//	   (GenericApplicationContext)applicationContext.setResourceLoader(resourceLoader);
//		applicationContext.setResourceLoader(applicationContext);

		class MyLaunchedURLClassLoader extends URLClassLoader {
			public MyLaunchedURLClassLoader(URL[] urls, ClassLoader parent) {
				super(urls, parent);
			}

			protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
				if (name.indexOf("com.xue.test") >= 0) {
					System.out.println("---------------->" + name);
					byte[] b;
					try {
						b = getResourceAsStream(name.replace(".", "/").concat(".class")).readAllBytes();
						return defineClass(name, b, 0, b.length);
					} catch (IOException e) {
						e.printStackTrace();
					}

				}
				return super.loadClass(name, resolve);
			}

			public URL findResource(final String name) {// 这个不必要重写
				if (name.indexOf("com/xue/test/") >= 0) {
					System.out.println("findResource---------------->" + name);
				}
				return super.findResource(name);

			}

			public InputStream getResourceAsStream(String name) {
				if (name.indexOf("com/xue/test/") >= 0 && name.endsWith(".class")) {
					System.out.println("---------------->" + name);
					try {
						return new ByteArrayInputStream(
								Crypto.decrypt(Crypto.key, super.getResourceAsStream(name).readAllBytes()));
					} catch (IOException e) {
						e.printStackTrace();
					}

				}
				return super.getResourceAsStream(name);
			}

		}

		class MyDefaultResourceLoader extends PathMatchingResourcePatternResolver {
//			@Override
//			public Resource getResource(String location) {
//			  System.out.println("##########location###############"+location);
//			  return	super.getResource(location);
//			}
//
//			
//			protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
//					throws IOException {
//				System.out.println("##########doFindPathMatchingFileResources###############" + rootDirResource);
//				return super.doFindPathMatchingFileResources(rootDirResource,subPattern);
//			}
//			
//			
//			@Override
//			public Resource[] getResources(String locationPattern) throws IOException {
//				System.out.println("##########locationPattern###############" + locationPattern);
//				return super.getResources(locationPattern);
//
//			}

			protected Set<Resource> doFindPathMatchingJarResources(Resource rootDirResource, URL rootDirURL,
					String subPattern) throws IOException {
				//##########doFindPathMatchingJarResources###############jar:file:/D:/a.jar!/BOOT-INF/lib/demo20220728test-1.0.0.jar!/com/
//				System.out.println("##########doFindPathMatchingJarResources###############" + rootDirURL);
				Set<Resource> rs = super.doFindPathMatchingJarResources(rootDirResource, rootDirURL, subPattern);
				// 找到UrlResource 替换为 ByteArrayResource
				Iterator<Resource> it = rs.iterator();
				Set<Resource> newSouce = new HashSet<>();
				while (it.hasNext()) {
					Resource r = it.next();
//					System.out.println(r);
					if (r.getURI().toString().indexOf("com/xue/test/") >= 0) {//其他包不处理
						System.out.println(r.getURL()+"------"+r.getClass()+","+r.getClass()+",path="+r.getURL().getPath()+",File="+r.getURL().getFile());
						// URL
						// [jar:file:/D:/a.jar!/BOOT-INF/lib/demo20220728test-1.0.0.jar!/com/xue/test/Hello.class]
						// URL
						// [jar:file:/D:/a.jar!/BOOT-INF/lib/demo20220728test-1.0.0.jar!/com/xue/test/Hello1.class]
						// 这里可以从class loader加载
//						r = new ByteArrayResource(Crypto.decrypt(Crypto.key, r.getInputStream().readAllBytes()),	r.getFilename());
						//获取classloader 获取资源 getClassLoader().getResourceAsStream(subPattern)因为classloader已经解密过了
						String className=r.getURL().getFile();
						className=className.substring(className.lastIndexOf(".jar!/")+".jar!/".length());
						System.out.println("className->"+className);
						r=new ByteArrayResource(getClassLoader().getResourceAsStream(className).readAllBytes());
						newSouce.add(r);
						it.remove();

					}
				}
				rs.addAll(newSouce);
				return rs;
			}

		}
//		applicationContext.setClassLoader(Thread.currentThread().getContextClassLoader());
//		applicationContext.addProtocolResolver(new MyProtocolResolver());
		applicationContext.setResourceLoader(new MyDefaultResourceLoader());

//		URLClassLoader ul=(URLClassLoader) Thread.currentThread().getContextClassLoader();
//		Arrays.stream( ul.getURLs()).forEach((URL u)->System.out.println(u));

//		System.out.println("##########run Initializer###############"+Thread.currentThread().getContextClassLoader());
		System.out.println("##########run Initializer###############");
		System.out.println("##########run Initializer###############");
		System.out.println("##########run Initializer###############");
		System.out.println("##########run Initializer###############");

//		try {
//			testJar();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
	}

	public class MyProtocolResolver implements ProtocolResolver {

		@Override
		public Resource resolve(String location, ResourceLoader resourceLoader) {
			System.out.println(resourceLoader.getClass() + "===========MyProtocolResolver==============>" + location);

			if (location.startsWith("buffer:")) {
				System.out
						.println(resourceLoader.getClass() + "===========MyProtocolResolver==============>" + location);
				return resourceLoader.getResource(location.replace("my", "classpath"));
			}
			return null;
		}
	}

}
